package znet

import (
	"errors"
	"fmt"
	"net"
	"zinx-learn/utils"
	"zinx-learn/ziface"
)

//  Connection 结构体
type Connection struct {
	// 当前连接所属的server
	TcpServer ziface.IServer
	// 连接的套接字
	Conn *net.TCPConn
	// 当前连接到额全局id
	ConnId uint32
	// 当前连接的状态
	isClosed bool
	// 告知当前连接已经退出的channel
	ExitBufChan chan bool
	// 添加一个router 用于表明该连接的处理方法
	msgHandler ziface.IMsgHandler
	// 进行读写之间的分离通信 (无缓冲)
	msgChan chan []byte
	// 有缓冲的通道
	msgChanBuff chan []byte
}

var dp = NewDataPack()

func (c *Connection) GetConnectionMsg() (ziface.IMessage, error) {
	// 获取头长度
	message, err := dp.ConnToMsg(c.Conn)
	if err != nil {
		return nil, err
	}
	return message, nil
}

func (c *Connection) msgProcess(msg ziface.IMessage, buffed bool) error {
	// 判断连接是否关闭
	if c.isClosed {
		return errors.New("conn already closed")
	}
	data, err := dp.Pack(msg)
	if err != nil {
		fmt.Println("pack data error ", err.Error())
		c.ExitBufChan <- true
		return err
	}
	// 如果是缓冲的就写入带有缓冲的通道中 否者写入非缓冲的通道中
	if buffed {
		c.msgChanBuff <- data
	} else {
		c.msgChan <- data
	}
	return nil
}

func (c *Connection) SendMsg(msg ziface.IMessage) error {
	return c.msgProcess(msg, false)
}

func (c *Connection) SendBuffMsg(msg ziface.IMessage) error {
	return c.msgProcess(msg, true)
}

func (c *Connection) StartWriter() {
	fmt.Println("[start Writer goroutine]")
	defer fmt.Printf("remote client %s exited !\n", c.RemoteAddr().String())
	for {
		select {
		case data := <-c.msgChan:
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("sent data error ", err.Error())
				return
			}
		case data, ok := <-c.msgChanBuff:
			if ok {
				if _, err := c.Conn.Write(data); err != nil {
					fmt.Println("sent data error ", err.Error())
					return
				}
			} else {
				fmt.Println("msgBuffChan closed")
				break
			}

		case <-c.ExitBufChan:
			// 连接已经关闭
			return
		}
	}
}

func (c *Connection) StartReader() {
	fmt.Println("[Start Reader ...]")
	defer func() {
		c.Stop() // 关闭连接
		fmt.Printf("Client %s connection exit !\n", c.RemoteAddr().String())
	}()
	for {
		message, err := c.GetConnectionMsg()
		if err != nil {
			fmt.Println("GetConnectionMsg error", err.Error())
			c.ExitBufChan <- true
			return
		}
		request := NewRequest(c, message)
		if utils.GlobalObject.WorkPoolSize > 0 {
			fmt.Println("send request to taskQueue...")
			c.msgHandler.SendMsgToTaskQueue(request)
		} else {
			go c.msgHandler.DoMsgHandler(request)
		}
	}
}

func (c *Connection) Start() {
	// 读写分离
	go c.StartWriter()
	go c.StartReader()
	// 调用用户自定义的操作
	c.TcpServer.CallOnConnStart(c)
	// 阻塞等待退出信号
	select {
	case res := <-c.ExitBufChan:
		fmt.Println("connection exit status is ", res)
		return
	}
}

func (c *Connection) Stop() {
	if c.isClosed {
		return
	}
	// 删除连接
	c.isClosed = true
	c.TcpServer.GetConnManager().Remove(c)
	// 关闭的回调函数
	c.TcpServer.CallOnConnStop(c)
	err := c.Conn.Close()
	if err != nil {
		fmt.Println(err)
	}
	c.ExitBufChan <- true

	// 关闭该连接的全部管道
	close(c.ExitBufChan)
	// 关闭通信的chan
	close(c.msgChan)

}

func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

func (c *Connection) GetConnectionID() uint32 {
	return c.ConnId
}

func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

// NewConnection 实例化一个Connection
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, handler ziface.IMsgHandler) *Connection {
	connection := &Connection{
		TcpServer:   server,
		Conn:        conn,
		ConnId:      connID,
		isClosed:    false,
		msgHandler:  handler,
		ExitBufChan: make(chan bool, 1),
		msgChan:     make(chan []byte),
		msgChanBuff: make(chan []byte, utils.GlobalObject.MaxMsgChanLen),
	}
	connection.TcpServer.GetConnManager().Add(connection)
	return connection
}
